from ConfigParser import RawConfigParser as ConfigParser
import imp, string, binascii, re

from twisted.internet.protocol import Protocol
from twisted.internet import reactor

from pankakes import logger
from pankakes.logger import log

class PankakeProtocol(Protocol):		
	def connectionMade(self):
		log("Incoming connection recieved.", logger.INFO)
		self.buffer = "" # prepare the buffer for this client's data
		self.commands = {}
		try:
			self.id = self.factory.claimId(self) # get a unique ID from the factory, also checks to make sure the server isn't full
			log("%s%i claimed ID: %i"%(self.factory.default_nick,self.id,self.id), logger.INFO)
			self.send(self.factory.welcome_message)
		except ServerFull:
			self.send('Sorry, the server is quite full.')
			log("Server is full, denying incoming client.", logger.WARNING)
			reactor.callLater(0.2, self.transport.loseConnection)
			return
		self.nickname = "%s%i"%(self.factory.default_nick,self.id)
		self.load_commands()
		
	def load_commands(self):
		settings = ConfigParser()
		settings.read('config.ini') #open command file with ConfigParser object
		cmd_list = settings.items('commands')
		for cmd in cmd_list:
			if int(cmd[1]) > 0:
				name = cmd[0]
				try:
					fp, pathname, descrip = imp.find_module(name, ['pankakes/commands']) # imp module takes care of advanced importing, so you can import filenames unknown at compile time
					try:
						obj = imp.load_module(name,fp,pathname,descrip)
						obj.log = log
						obj.logger = logger
						new_cmd = obj.command()
						new_cmd.protocol = self
						self.commands[name] = [obj,new_cmd]
					except:
						pass
				except:
					pass
		
	def connectionLost(self, reason):
		log("%s (Client %i) disconnected."%(self.nickname,self.id), logger.INFO)
		self.factory.releaseId(self.id) #free up id for future connections
		
	def send(self,data):
		self.transport.write(data+"\0") #must append 0 so Flash knows string has terminated
		
	def sendAll(self,data):
		for c in self.factory.clients:
			self.factory.clients[c].send(data)
	
	def dataReceived(self, data):
		self.buffer += data
		while self.buffer:
			if len(self.buffer) < 6: #not enough data to process type/length values
				break
			pattern = "[0-9A-F]"
			if not re.search(pattern,self.buffer[0]): #bad data, discard first char until it matches
				self.buffer = self.buffer[1:]
				continue
			type = int(float.fromhex(self.buffer[:2]))
			length = int(float.fromhex(self.buffer[2:4]) * 255 + float.fromhex(self.buffer[4:6]))
			if len(self.buffer[6:]) < length * 2:
				break	#Haven't received all of the message data yet
			chunk = self.buffer[6:6+length * 2]
			self.buffer = self.buffer[len(chunk)+6:]
			msg = binascii.unhexlify(chunk)
			log("%s: %s"%(self.nickname,msg), logger.MESSAGE)
			if msg[0] == '/':
				self.process_command(msg)
			else:
				self.process_message(msg)
			
	def process_message(self,msg):
		self.sendAll("%s: %s"%(self.nickname,msg))
		
	def process_command(self,cmd):
		cmd = cmd[1:]
		cmdlist = string.split(cmd)
		if cmdlist[0] in self.commands:
			self.commands[cmdlist[0]][1].do(cmd)
			
		